Простые приложения на PHP
Простые приложения на PHP
PHP (Hypertext Preprocessor) — это язык программирования общего назначения, который изначально создавался для веб-разработки. Однако его возможности выходят далеко за рамки обработки веб-страниц. Язык предоставляет мощный инструментарий для работы с файловой системой, сетевыми протоколами, базами данных и операционной средой. В этом разделе рассматриваются практические примеры создания консольных утилит и простых серверных приложений.
Генератор паролей
Этот пример демонстрирует работу со строками, массивами символов и функциями генерации случайных чисел. Конструкция random_int является криптографически стойкой альтернативой функции rand.
Код программы
<?php
/**
* Генератор надежных паролей
*
* Параметры:
* - длина пароля (по умолчанию 16)
* - включение цифр (true по умолчанию)
* - включение спецсимволов (true по умолчанию)
*/
function generatePassword(int $length = 16, bool $useDigits = true, bool $useSpecial = true): string {
// Определение наборов символов
$lowercase = 'abcdefghijklmnopqrstuvwxyz';
$uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$digits = '0123456789';
$special = '!@#$%^&*()_+-=[]{}|;:,.<>?';
$characterSet = $lowercase . $uppercase;
if ($useDigits) {
$characterSet .= $digits;
}
if ($useSpecial) {
$characterSet .= $special;
}
$maxLength = strlen($characterSet);
$password = '';
for ($i = 0; $i < $length; $i++) {
// Генерация безопасного случайного индекса
$index = random_int(0, $maxLength - 1);
$password .= $characterSet[$index];
}
return $password;
}
// Пример использования
echo "Сгенерированный пароль: " . generatePassword(20, true, true) . PHP_EOL;
echo "Пароль без спецсимволов: " . generatePassword(12, true, false) . PHP_EOL;
?>
Разбор логики
Программа формирует итоговую строку из доступных символов. Массивы строк объединяются в одну переменную $characterSet в зависимости от выбранных опций. Цикл for выполняет итерации ровно столько раз, сколько указана длина пароля. На каждой итерации вызывается функция random_int, которая возвращает целое число в заданном диапазоне. Индекс полученного числа используется как позиция символа в строке набора. Результат последовательно добавляется к переменной $password.
Сортировщик текстового файла
Пример показывает чтение содержимого файла в память, обработку массива строк и запись результата обратно в файл или вывод в консоль.
Код программы
<?php
/**
* Сортировка строк из текстового файла
*
* Использование: php sort_file.php input.txt output_sorted.txt
*/
if ($argc < 2) {
die("Использование: php sort_file.php <input_file> [output_file]\n");
}
$inputFile = $argv[1];
if (!file_exists($inputFile)) {
die("Ошибка: Файл не найден: {$inputFile}\n");
}
// Чтение всех строк файла в массив
$lines = file($inputFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (empty($lines)) {
echo "Файл пуст или не содержит данных.\n";
exit(0);
}
// Сортировка массива по алфавиту (режим сортировки: естественный порядок)
sort($lines, SORT_STRING | SORT_FLAG_CASE);
// Определение выходного файла
$outputFile = $argc > 2 ? $argv[2] : null;
if ($outputFile) {
// Запись отсортированных строк в новый файл
$result = implode(PHP_EOL, $lines) . PHP_EOL;
file_put_contents($outputFile, $result);
echo "Данные успешно сохранены в: {$outputFile}\n";
} else {
// Вывод в консоль
foreach ($lines as $line) {
echo $line . PHP_EOL;
}
}
?>
Разбор логики
Функция file загружает содержимое файла в массив строк. Флаги FILE_IGNORE_NEW_LINES удаляют символ переноса строки в конце каждой записи, а FILE_SKIP_EMPTY_LINES игнорирует пустые строки. Функция sort упорядочивает элементы массива. Параметр SORT_FLAG_CASE обеспечивает регистронезависимую сортировку. Функция implode объединяет массив обратно в единую строку, разделяя элементы символом переноса строки (PHP_EOL). Функция file_put_contents записывает результат в целевой файл.
Консольный калькулятор
Пример реализует базовую арифметику с обработкой ввода пользователя и проверкой деления на ноль.
Код программы
<?php
/**
* Простой консольный калькулятор
* Поддерживаемые операции: +, -, *, /
*/
echo "Консольный калькулятор\n";
echo "Введите первое число: ";
$num1 = trim(fgets(STDIN));
echo "Введите операцию (+, -, *, /): ";
$operation = trim(fgets(STDIN));
echo "Введите второе число: ";
$num2 = trim(fgets(STDIN));
$result = 0;
$isValid = true;
switch ($operation) {
case '+':
$result = $num1 + $num2;
break;
case '-':
$result = $num1 - $num2;
break;
case '*':
$result = $num1 * $num2;
break;
case '/':
if ($num2 == 0) {
echo "Ошибка: Деление на ноль невозможно.\n";
$isValid = false;
} else {
$result = $num1 / $num2;
}
break;
default:
echo "Ошибка: Неверная операция.\n";
$isValid = false;
break;
}
if ($isValid) {
echo "Результат: {$num1} {$operation} {$num2} = {$result}\n";
}
?>
Разбор логики
Ввод данных осуществляется через стандартный поток ввода STDIN с помощью функции fgets. Функция trim удаляет пробелы и символы новой строки, оставшиеся после ввода. Переменные $num1 и $num2 приводятся к числовому типу автоматически при выполнении математических операций. Конструкция switch выбирает ветку выполнения кода в зависимости от введенной операции. Проверка делителя на ноль предотвращает возникновение ошибки выполнения.
Трекер задач в JSON
Пример иллюстрирует сериализацию и десериализацию данных, работу с файловой системой и создание структуры данных для хранения информации.
Код программы
<?php
/**
* Трекер задач с сохранением в JSON
*
* Команды:
* - add <задача>: Добавить новую задачу
* - list: Показать все задачи
* - clear: Очистить список
*/
$dataFile = 'tasks.json';
$tasks = [];
// Загрузка существующих данных
if (file_exists($dataFile)) {
$content = file_get_contents($dataFile);
$tasks = json_decode($content, true) ?: [];
}
$command = $argv[1] ?? '';
$taskText = $argv[2] ?? '';
switch ($command) {
case 'add':
if (empty($taskText)) {
echo "Ошибка: Укажите текст задачи.\n";
exit(1);
}
$newTask = [
'id' => uniqid(),
'text' => $taskText,
'created_at' => date('Y-m-d H:i:s')
];
$tasks[] = $newTask;
saveTasks($tasks);
echo "Задача добавлена.\n";
break;
case 'list':
if (empty($tasks)) {
echo "Список задач пуст.\n";
} else {
echo "Список задач:\n";
foreach ($tasks as $task) {
echo "- [{$task['id']}] {$task['text']} (создано: {$task['created_at']})\n";
}
}
break;
case 'clear':
$tasks = [];
saveTasks($tasks);
echo "Список задач очищен.\n";
break;
default:
echo "Неизвестная команда. Используйте: add, list, clear\n";
break;
}
function saveTasks(array $tasks): void {
global $dataFile;
$jsonContent = json_encode($tasks, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents($dataFile, $jsonContent);
}
?>
Разбор логики
Функция json_decode преобразует строку JSON в ассоциативный массив PHP. Параметр true гарантирует получение массива вместо объекта. Функция json_encode выполняет обратное преобразование, превращая массив в строку формата JSON. Флаги JSON_PRETTY_PRINT и JSON_UNESCAPED_UNICODE обеспечивают читаемость файла и корректное отображение кириллицы. Структура задачи включает уникальный идентификатор, текст и временную метку.
Простой HTTP-сервер и клиент
PHP позволяет создавать простые веб-серверы и обрабатывать входящие запросы. Ниже представлен пример минимального сервера и клиента для демонстрации взаимодействия.
Сервер (server.php)
<?php
/**
* Минимальный HTTP-сервер на PHP
* Запуск: php server.php 8080
*/
$host = '127.0.0.1';
$port = $argv[1] ?? 8080;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $host, $port);
socket_listen($socket);
echo "Сервер запущен на http://{$host}:{$port}\n";
while (true) {
$client = socket_accept($socket);
if ($client === false) {
continue;
}
$request = socket_read($client, 2048);
$response = "HTTP/1.1 200 OK\r\n";
$response .= "Content-Type: text/plain\r\n";
$response .= "\r\n";
$response .= "Hello from PHP Server! Request received.";
socket_write($client, $response, strlen($response));
socket_close($client);
}
socket_close($socket);
?>
Клиент (client.php)
<?php
/**
* Простой HTTP-клиент
* Использование: php client.php <host> <port>
*/
$host = $argv[1] ?? '127.0.0.1';
$port = $argv[2] ?? 8080;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!socket_connect($socket, $host, $port)) {
die("Ошибка подключения к серверу\n");
}
$request = "GET / HTTP/1.1\r\nHost: {$host}:{$port}\r\n\r\n";
socket_write($socket, $request, strlen($request));
$response = socket_read($socket, 2048);
echo "Ответ от сервера:\n{$response}\n";
socket_close($socket);
?>
Разбор логики
Функции socket_create, socket_bind, socket_listen создают и настраивают сокет сервера. Функция socket_accept ожидает входящее подключение. Функция socket_read считывает данные от клиента. Функция socket_write отправляет ответ. В клиенте аналогичные функции используются для установления соединения и отправки запроса.
Отправитель HTTP-запросов
Утилита для отправки POST-запросов с данными в формате JSON.
Код программы
<?php
/**
* Отправитель HTTP-запросов
* Использование: php send_request.php <url> <json_data>
*/
$url = $argv[1] ?? '';
$jsonData = $argv[2] ?? '{}';
if (empty($url)) {
die("Укажите URL адрес\n");
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $jsonData,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: ' . strlen($jsonData)
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
echo "Ошибка: {$error}\n";
} else {
echo "Статус: {$httpCode}\n";
echo "Ответ: {$response}\n";
}
?>
Разбор логики
Библиотека cURL используется для сетевого взаимодействия. Функция curl_init инициализирует сеанс. Массив параметров передается в curl_setopt_array. Флаг CURLOPT_POST указывает метод отправки. Параметр CURLOPT_POSTFIELDS содержит тело запроса. Функция curl_exec выполняет запрос. Функция curl_getinfo получает код ответа сервера.
Утилита для сканирования директорий
Пример обхода папок и файлов с получением их атрибутов.
Код программы
<?php
/**
* Сканирование директории
* Использование: php scan_dir.php <путь>
*/
$path = $argv[1] ?? '.';
if (!is_dir($path)) {
die("Ошибка: Путь не существует или не является директорией\n");
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
echo "Сканирование директории: {$path}\n";
echo str_repeat('-', 40) . "\n";
foreach ($iterator as $file) {
$relativePath = $file->getRelativePathname();
$size = $file->getSize();
$type = $file->isDir() ? '[DIR]' : '[FILE]';
$permissions = substr(sprintf('%o', $file->getPerms()), -4);
echo "{$type} {$relativePath} | Размер: {$size} байт | Права: {$permissions}\n";
}
?>
Разбор логики
Класс RecursiveDirectoryIterator создает итератор для доступа к файлам и поддиректориям. Класс RecursiveIteratorIterator управляет рекурсивным обходом. Метод getRelativePathname возвращает путь относительно корня. Метод getSize возвращает размер файла в байтах. Метод getPerms возвращает права доступа в восьмеричной системе счисления.
Скрипт для создания резервного копирования файлов
Автоматическое создание архивов с текущей датой в имени.
Код программы
<?php
/**
* Создание резервной копии
* Использование: php backup.php <путь_к_папке> <путь_для_резерва>
*/
$sourceDir = $argv[1] ?? '.';
$backupDir = $argv[2] ?? './backups';
$date = date('Y-m-d_H-i-s');
$backupName = "backup_{$date}.zip";
$backupPath = $backupDir . '/' . $backupName;
if (!is_dir($sourceDir)) {
die("Ошибка: Исходная директория не найдена\n");
}
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
$zip = new ZipArchive();
if ($zip->open($backupPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
die("Ошибка: Не удалось создать архив\n");
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $file) {
$filePath = $file->getPathname();
$relativePath = $file->getRelativePathname();
if ($file->isDir()) {
$zip->addEmptyDir($relativePath);
} else {
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
echo "Резервная копия создана: {$backupPath}\n";
echo "Размер архива: " . filesize($backupPath) . " байт\n";
?>
Разбор логики
Класс ZipArchive работает с ZIP-архивами. Метод open открывает или создает архив. Метод addEmptyDir добавляет пустую директорию в архив. Метод addFile добавляет файл с указанием относительного пути внутри архива. Функция filesize определяет размер созданного файла.
Мониторинг дискового пространства
Проверка свободного места на дисках.
Код программы
<?php
/**
* Мониторинг дискового пространства
*/
$diskInfo = disk_free_space('/');
$totalSpace = disk_total_space('/');
$usedSpace = $totalSpace - $diskInfo;
$percentUsed = round(($usedSpace / $totalSpace) * 100, 2);
echo "Диск: /\n";
echo "Всего места: " . formatBytes($totalSpace) . "\n";
echo "Занято: " . formatBytes($usedSpace) . " ({$percentUsed}%)\n";
echo "Свободно: " . formatBytes($diskInfo) . "\n";
function formatBytes(int $bytes, int $precision = 2): string {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
?>
Разбор логики
Функция disk_free_space возвращает количество свободных байт. Функция disk_total_space возвращает общий объем диска. Функция log вычисляет натуральный логарифм для определения порядка величины. Цикл выбора единицы измерения использует массив units.
Парсер URL и проверка доступности ресурса
Анализ структуры URL и проверка HTTP-статуса.
Код программы
<?php
/**
* Парсер URL и проверка доступности
* Использование: php check_url.php <url>
*/
$url = $argv[1] ?? '';
if (empty($url)) {
die("Укажите URL\n");
}
$parsedUrl = parse_url($url);
echo "Парсинг URL: {$url}\n";
echo "Протокол: " . ($parsedUrl['scheme'] ?? 'нет') . "\n";
echo "Хост: " . ($parsedUrl['host'] ?? 'нет') . "\n";
echo "Порт: " . ($parsedUrl['port'] ?? 'нет') . "\n";
echo "Путь: " . ($parsedUrl['path'] ?? '/') . "\n";
echo "Запрос: " . ($parsedUrl['query'] ?? '') . "\n";
// Проверка доступности
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_NOBODY => true, // Только заголовки
CURLOPT_TIMEOUT => 5
]);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Статус доступности: " . getStatusMessage($httpCode) . "\n";
function getStatusMessage(int $code): string {
switch ($code) {
case 200: return "OK";
case 404: return "Не найдено";
case 500: return "Ошибка сервера";
default: return "Статус {$code}";
}
}
?>
Разбор логики
Функция parse_url разбивает строку URL на компоненты. Массив результатов содержит ключи scheme, host, port, path, query. Функция curl_init создает запрос с флагом CURLOPT_NOBODY, чтобы не скачивать тело ответа. Функция curl_getinfo извлекает код ответа.
Конвертер форматов дат
Преобразование дат между различными форматами.
Код программы
<?php
/**
* Конвертер форматов дат
* Использование: php date_converter.php <дата> <формат_ввода> <формат_вывода>
*/
$dateString = $argv[1] ?? '';
$inputFormat = $argv[2] ?? 'Y-m-d';
$outputFormat = $argv[3] ?? 'd.m.Y';
if (empty($dateString)) {
die("Укажите дату\n");
}
$timestamp = strtotime($dateString);
if ($timestamp === false) {
die("Ошибка: Невалидный формат даты\n");
}
$formattedDate = date($outputFormat, $timestamp);
echo "Ввод: {$dateString} ({$inputFormat})\n";
echo "Вывод: {$formattedDate} ({$outputFormat})\n";
?>
Разбор логики
Функция strtotime преобразует строку в Unix-временную метку. Функция date форматирует метку времени согласно заданному шаблону. Шаблоны поддерживают символы Y (год), m (месяц), d (день), H (часы), i (минуты).
Утилита для просмотра запущенных процессов
Отображение списка активных процессов системы.
Код программы
<?php
/**
* Просмотр запущенных процессов
* Работает только в Linux/Unix системах
*/
if (PHP_OS_FAMILY !== 'Linux' && PHP_OS_FAMILY !== 'BSD') {
die("Эта утилита работает только в Linux или BSD системах\n");
}
$processes = shell_exec('ps aux');
$lines = explode("\n", trim($processes));
echo "ID\t\tUSER\t\tCPU%\tMEM%\tCOMMAND\n";
echo str_repeat('-', 80) . "\n";
array_shift($lines); // Удаление заголовка ps
foreach ($lines as $line) {
$parts = preg_split('/\s+/', trim($line));
if (count($parts) >= 11) {
$pid = $parts[1];
$user = $parts[2];
$cpu = $parts[2]; // Индекс может варьироваться в зависимости от системы, здесь упрощено
$mem = $parts[3];
$cmd = $parts[10] ?? '';
// Корректировка индексов для стандартного ps aux
$pid = $parts[1];
$user = $parts[2];
$cpu = $parts[2]; // Это поле CPU%
$mem = $parts[3]; // Это поле MEM%
$cmd = implode(' ', array_slice($parts, 10));
echo "{$pid}\t\t{$user}\t\t{$cpu}\t\t{$mem}\t\t{$cmd}\n";
}
}
?>
Разбор логики
Функция shell_exec выполняет внешнюю команду ps aux и возвращает её вывод. Функция explode разделяет вывод на строки. Функция preg_split разделяет строку по пробельным символам. Массив $parts содержит колонки процесса. Индексы массива соответствуют порядку вывода команды ps.
Характерный пример для языка PHP
PHP обладает уникальной особенностью — возможностью выполнения кода непосредственно внутри HTML-страниц с использованием тегов <?php ... ?>. Этот подход позволяет динамически формировать контент страницы на основе данных, полученных от пользователя или базы данных.
Пример: Динамическая страница с формой
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Динамическая форма</title>
</head>
<body>
<h1>Обратная связь</h1>
<?php
$message = '';
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$comment = trim($_POST['comment'] ?? '');
if (empty($name)) {
$errors[] = 'Имя обязательно.';
}
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Введите корректный email.';
}
if (empty($comment)) {
$errors[] = 'Комментарий обязателен.';
}
if (empty($errors)) {
$message = "Спасибо, {$name}! Ваша заявка принята.";
// Здесь могла бы быть логика сохранения в базу данных
}
}
?>
<?php if (!empty($errors)): ?>
<div style="color: red;">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php echo htmlspecialchars($error); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if ($message): ?>
<div style="color: green;">
<p><?php echo htmlspecialchars($message); ?></p>
</div>
<?php endif; ?>
<form method="POST" action="">
<label>Имя:<br><input type="text" name="name"></label><br><br>
<label>Email:<br><input type="email" name="email"></label><br><br>
<label>Комментарий:<br><textarea name="comment"></textarea></label><br><br>
<button type="submit">Отправить</button>
</form>
</body>
</html>
Разбор логики
Фрагменты кода внутри тегов <?php ... ?> выполняются на сервере до отправки HTML-кода браузеру. Переменная $_SERVER['REQUEST_METHOD'] проверяет тип HTTP-запроса. Массив $_POST содержит данные, переданные пользователем. Функция htmlspecialchars экранирует специальные символы для предотвращения XSS-атак. Логика проверки данных выполняется до формирования HTML-ответа. Условные конструкции if определяют, какие блоки контента будут выведены.
Этот пример демонстрирует интеграцию логики обработки данных с представлением пользовательского интерфейса, что является фундаментальной концепцией разработки на PHP.